package handlers

import (
	"net/http"

	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/middleware"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
)

type AuthHandler struct {
	jwtSecret string
}

func NewAuthHandler(jwtSecret string) *AuthHandler {
	return &AuthHandler{jwtSecret: jwtSecret}
}

// Mock user storage (in production, this would be a database)
var mockUsers = map[string]mockUser{
	"admin@example.com": {
		ID:       "user-001",
		Username: "admin",
		Email:    "admin@example.com",
		Password: "$2a$10$aaFLpjXjsmSB3THV3.dt3O2pDPUyosx1d23TQ6tSvA2Rk2apbjpAq", // "admin123"
		Role:     "admin",
	},
	"user@example.com": {
		ID:       "user-002",
		Username: "user",
		Email:    "user@example.com",
		Password: "$2a$10$NeRn40DLDSpRDuXeYbsfCuekCzlWauZ/14VViOi6yFiY1P5J9T6cO", // "user123"
		Role:     "user",
	},
}

type mockUser struct {
	ID       string
	Username string
	Email    string
	Password string
	Role     string
}

// Login handles POST /api/auth/login
func (h *AuthHandler) Login(c *gin.Context) {
	var req struct {
		Email    string `json:"email" binding:"required,email"`
		Password string `json:"password" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Find user by email
	user, exists := mockUsers[req.Email]
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
		return
	}

	// Verify password
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
		return
	}

	// Generate JWT token
	token, err := middleware.GenerateToken(user.ID, user.Username, user.Email, user.Role, h.jwtSecret, 24)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
		return
	}

	// Generate refresh token (valid for 7 days)
	refreshToken, err := middleware.GenerateToken(user.ID, user.Username, user.Email, user.Role, h.jwtSecret, 24*7)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate refresh token"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"accessToken":  token,
		"refreshToken": refreshToken,
		"user": gin.H{
			"id":       user.ID,
			"username": user.Username,
			"email":    user.Email,
			"role":     user.Role,
		},
	})
}

// Register handles POST /api/auth/register
func (h *AuthHandler) Register(c *gin.Context) {
	var req struct {
		Username string `json:"username" binding:"required"`
		Email    string `json:"email" binding:"required,email"`
		Password string `json:"password" binding:"required,min=6"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Check if user already exists
	if _, exists := mockUsers[req.Email]; exists {
		c.JSON(http.StatusConflict, gin.H{"error": "Email already registered"})
		return
	}

	// Hash password
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
		return
	}

	// Create new user
	newUser := mockUser{
		ID:       uuid.New().String(),
		Username: req.Username,
		Email:    req.Email,
		Password: string(hashedPassword),
		Role:     "user", // default role
	}

	// Save to mock storage
	mockUsers[req.Email] = newUser

	// Generate JWT token
	token, err := middleware.GenerateToken(newUser.ID, newUser.Username, newUser.Email, newUser.Role, h.jwtSecret, 24)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
		return
	}

	refreshToken, err := middleware.GenerateToken(newUser.ID, newUser.Username, newUser.Email, newUser.Role, h.jwtSecret, 24*7)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate refresh token"})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"accessToken":  token,
		"refreshToken": refreshToken,
		"user": gin.H{
			"id":       newUser.ID,
			"username": newUser.Username,
			"email":    newUser.Email,
			"role":     newUser.Role,
		},
	})
}

// RefreshToken handles POST /api/auth/refresh
func (h *AuthHandler) RefreshToken(c *gin.Context) {
	var req struct {
		RefreshToken string `json:"refreshToken" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Validate refresh token
	claims, err := middleware.ValidateToken(req.RefreshToken, h.jwtSecret)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired refresh token"})
		return
	}

	// Generate new access token
	token, err := middleware.GenerateToken(claims.UserID, claims.Username, claims.Email, claims.Role, h.jwtSecret, 24)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"accessToken": token,
	})
}

// GetProfile handles GET /api/auth/profile
func (h *AuthHandler) GetProfile(c *gin.Context) {
	// Get user info from context (set by JWT middleware)
	userID, _ := c.Get("userId")
	username, _ := c.Get("username")
	email, _ := c.Get("email")
	role, _ := c.Get("role")

	c.JSON(http.StatusOK, gin.H{
		"user": gin.H{
			"id":       userID,
			"username": username,
			"email":    email,
			"role":     role,
		},
	})
}

// Logout handles POST /api/auth/logout
func (h *AuthHandler) Logout(c *gin.Context) {
	// In a stateless JWT implementation, logout is handled client-side
	// The client should remove the token from storage
	// For server-side logout, you would typically:
	// 1. Add the token to a blacklist/revocation list
	// 2. Or use a token versioning system in the database
	// For now, we'll just return success
	c.JSON(http.StatusOK, gin.H{
		"message": "Logged out successfully",
	})
}
